home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / serien / purity / nr.12 / workshop / pascalkursiv.txt < prev    next >
Text File  |  1995-04-21  |  15KB  |  351 lines

  1.  
  2.  ========================================================================
  3.  =                  Systemprogrammierung in PCQ-Pascal                  =
  4.  =               Kurs für AmigaGadget/Purity - Teil IV                  =
  5.  ========================================================================
  6.  
  7.  
  8.  Bisherige Kursteile :
  9.  
  10.     Teil I   : Voraussetzungen,Screens,Windows
  11.     Teil II  : Einfache Grafikausgabe
  12.     Teil III : Weitere Grafikbefehle, einige nützliche Routinen
  13.  
  14.  Erst einmal ein fröhliches Hallo an all die interessierten Pascal-
  15.  Programmierer, die sich wieder zusammengefunden haben, um hier der Lust
  16.  der Systemprogrammierung zu frönen.
  17.  
  18.  Einen wunderschönen guten Morgen ! Heute wollen wir endlich damit beginnen,
  19.  den Anwender in unsere Programme mit einzubeziehen. Da wir Hand in
  20.  Hand mit Intuition arbeiten, existiert da für uns natürlich ein Element,
  21.  das uns bei geringem Aufwand ein großes Ergebniss liefert - die
  22.  IntuitionMessage oder kurz IntuiMessage. Sie arbeitet über sogenannte
  23.  IDCMPs, IntuitionDirectCommunictionMessagePorts.
  24.  
  25.  Wie die meisten Intuition-Strukturen ist sie in
  26.  "Include:Intuition/Intuition.i" definiert und siehr folgendermaßen aus :
  27.  
  28.     IntuiMessage = record
  29.         ExecMessage     : Message;      die "eigentliche" Messagem wie sie
  30.                                         von Exec verwaltet wird
  31.         Class           : Integer;      nähere Informationen über die Art
  32.                                         der Message (z.dt. Nachricht)
  33.         Code            : Short;        speziellere Informationen über die
  34.                                         Message, z.B. bei gedrückten
  35.                                         Mausknopf, ob er losgelassen wurde
  36.                                         oder gedrückt, etc.
  37.         Qualifier       : Short;        bei Tastaturabfrage Informationen
  38.                                         über benutzte Sondertasten etc.
  39.         IAddress        : Address;      enthält spezielle Informationen, wie
  40.                                         z.B. die Adresse des aktivierten
  41.                                         Gadgets
  42.         MouseX,                         die Mauskoordinaten, bei Empfang
  43.         MouseY          : Short;        der Message
  44.         Seconds,                        die Werte der Systemuhr zur Zeit
  45.         Micros          : Integer;      des Empfangs der Nachricht
  46.         IDCMPWindow     : Address;      die Adresse des Windows, aus dem
  47.                                         die Message kam
  48.         SpecialLink     : ^IntuiMessage;
  49.     end;
  50.     IntuiMessagePtr = ^IntuiMessage;
  51.  
  52.   Sieht komplex und kompliziert aus, erweist sich jedoch im täglichen
  53.   Gebrauch als sehr praktisch und einfach.
  54.  
  55.   Wie kommen wir nun an so eine Message ran ?
  56.  
  57.   Es empfiehlt sich - der Einfachkeit halber - ersteinmal mit den uns
  58.   aus diesem Kurs schon bekannten Elementen zu arbeiten - in unserem
  59.   Fall mit Windows.
  60.   Wir erinnern uns, oder lesen es nach, daß wir im Teil 1 dieses Kurses
  61.   ein Element der NewWindow-Struktur ausdrücklich aufgespart haben, eine
  62.   Integer-Variable des Namens IDCMPFlags. Nun können wir etwas mehr damit
  63.   anfangen, wissen wir doch jetzt grob, was IDCMP für uns bedeutet.
  64.   Die Vermutung liegt nahe, daß man dieses Feld mit Informationen
  65.   füllen kann, die die Art der IntuiMessages bestimmt, die in diesem
  66.   Window empfangen werden können. Das ist sehr sinnvoll, da es eine
  67.   Unzahl von IntuiMessages gibt und es für den Programmierer enorm
  68.   aufwendig wäre, stets nur die gewünschten herauszufiltern. Eine
  69.   kurze Übersicht über die wichtigsten der IDCMP-Flags, natürlich in
  70.   "Include:Intuition/Intuition.i" zu finden :
  71.  
  72.     SIZEVERIFY_f        wenn der Benutzer versucht, die Größe des
  73.                         Fensters zu ändern, wird diese Message gesendet.
  74.                         Intuition wartet so lange, bis man diese
  75.                         IntuiMsg beantwortet hat.
  76.     NEWSIZE_f           IntuiMsg wird gesendet, wenn die Größe des
  77.                         Fensters vom Benutzer geändert wurde
  78.     REFRESHWINDOW_f     spielt bei Windows eine Rolle, die nur über
  79.                         SIMPLE_REFRESH verfügen und wird gesendet, wenn der
  80.                         Fensterinhalt zerstört wurde, der Programmierer sich
  81.                         also darum kümmern muß, ihn wieder aufzubauen.
  82.     MOUSEBUTTONS_f      diese IntuiMsg erhält man, wenn der Benutzer
  83.                         die linke Maustaste gedrückt hat. Hat man auch
  84.                         noch das Flag RMBTRAP in der entsprechenden
  85.                         NewWindowStruktur definiert, so erhält man diese
  86.                         Message auch bei Betätigung des rechten Mausknopfs.
  87.                         Nähere Informationen zu der Art dieser Message
  88.                         stehen im Feld Code des IntuiMsg :
  89.                           SELECTUP   : linke Maustaste losgelassen
  90.                           SELECTDOWN : linke Maustaste gedrückt
  91.                           MENUUP     : rechte Maustaste losgelassen
  92.                           MENUDOWN   : rechte Maustaste gedrückt
  93.     MOUSEMOVE_f         sollte gesetzt sein, wenn man in der IntuiMessage
  94.                         -Struktur die Mauskoordinaten aktualisiert
  95.                         haben möchte.
  96.     GADGETDOWN_f        ein Gadget wurde angeklickt
  97.     GADGETUP_f          ein Gadget wurde wieder losgelassen (die linke
  98.                         Maustaste wurde über einem Gadget losgelassen)
  99.     MENUPICK_f          ein Menüpunkt wurde ausgewählt, nähere
  100.                         Informationen darüber in Variable Code und wenn wir
  101.                         uns in diesem Kurs näher damit beschäftigen.
  102.     CLOSEWINDOW_f       das CloseGadget des Windows wurde angewählt
  103.     RAWKEY_f            eine Taste wurde gedrückt. Der Tastaturcode (nicht
  104.                         der Ascii-Code) befindet sich in der Variable Code.
  105.     NEWPREFS_f          es wurden einige Preferences-Werte vom Benutzer
  106.                         geändert
  107.     DISKINSERTED_f      eine Diskette wurde in ein Laufwerk eingelegt
  108.     DISKREMOVED_f       eine Diskette wurde einem Laufwerk entnommen
  109.     ACTIVEWINDOW_f      ein Fenster wurde aktiviert
  110.     INACTIVEWINDOW_f    ein Fenster wurde deaktiviert
  111.     VANILLAKEY_f        wie RAWKEY_f, nur daß diesmal der ASCII-Code
  112.                         in Code gespeichert wird
  113.     INTUITICKS_f        solange das Fenster geöffnet ist, behämmert
  114.                         Intuition den Programmierer mit diesem Signal
  115.  
  116.   Das "_f" am Ende dient übrigens dazu, die Flags von oft gleichnamigen
  117.   Intuition-Prozeduren und -Funktionen zu unterscheiden.
  118.   Die Flags müssen in das IDCMP-Feld der NewWindow-Struktur eingetragen
  119.   werden und stehen dei Empfang einer Nachricht im Feld "Class" !
  120.  
  121.   Nun kommen wir zu einem Beispiel :
  122.  
  123.   Wir wollen ein Fenster aufmachen, das durch Druck auf das Closegadget
  124.   geschlossen wird und dabei das Programm beendet.
  125.   "Einfach" möchte man vorschnell denken und man hätte sogar recht :-)
  126.  
  127.   Denken wir uns die Schritte durch :
  128.  
  129.   1. Fensterstruktur festlegen, dabei muß das Feld IDCMPFlags mit
  130.      CLOSEWINDOW_f gefüllt werden.
  131.   2. Öffnen des Fensters.
  132.   3. Auf die Message warten, daß das Gadget betätigt wurde.
  133.   4. Fenster schließen und Ende.
  134.  
  135.   Davon abgesehen, daß in Sachen Punkt 3 noch keine weiteren Informationen
  136.   gegeben sind, ist in diesem Ablaufplan ein Fehler. Aufmerksame Leser
  137.   (Folge I !!) werden ihn bemerkt haben.
  138.   Er liegt in Punkt 1 :
  139.   der User könnte so lange er wollte die linke obere Ecke des Fensters
  140.   anstarren, es würde einfach kein CloseGadget entstehen. Dazu muß man
  141.   nämlich bekanntermaßen in der NewWindow-Struktur das WINDOWCLOSE-Flag
  142.   setzen !
  143.  
  144.   Nun zu dem alles entscheidenden Punkt 3. Hier stellt Exec uns
  145.   z.B. folgende Befehle zur Verfügung :
  146.  
  147.   MessagePtr := GetMsg(port : MsgPortPtr);
  148.  
  149.                 Diese Funktion holt die nächste Message aus einem
  150.                 MessagePort, einer Art "Hafen" für ankommende Nachrichten.
  151.                 Sie stehen dort Schlange, bis jemand sie nimmt und
  152.                 zurückschickt.
  153.                 Da die Message-Befehle in "Include:exec/Ports.i"
  154.                 definiert sind (wird allerdings von "Include:intuition/
  155.                 intuition.i" automatisch eingebunden), müssen es nicht
  156.                 unbedingt IntuiMessages sein, die empfangen werden.
  157.                 GetMsg liefert also keinen IntuiMessagePtr zurück !
  158.                 Darauf muß geachtet werden, da sonst bei der
  159.                 Compilierung eine Fehlermeldung auftritt !
  160.                 Der MsgPort, an den "unsere" Messages ankommen, befindet
  161.                 sich im Window und heißt "UserPort", weil er eben die
  162.                 Schnittstelle zum User, dem Anwender, ist.
  163.  
  164.   ReplyMsg(mess : MessagePtr);
  165.  
  166.                 Wie oben beschrieben, sollten einmal angenommene
  167.                 Messages wieder zurückgeschickt werden, da sie
  168.                 Speicherplatz belegen. Bildlich gesprochen, gammeln
  169.                 sie immer noch in der Schlange herum....
  170.                 Hier gilt wieder : Exec bezieht sich NICHT auf
  171.                 IntuiMessages !
  172.  
  173.   Nun kommen wir zu einem häufigen Problem im Umgang mit Messages, das
  174.   auch in unserem Programm auftritt. Wir wollen ja warten, bis der User
  175.   sich bequemt, das Gadget anzuklicken. Wie realisiert man nun das ?
  176.   Nun ja, eine Möglichkeit wäre
  177.  
  178.     REPEAT
  179.      myintuimessage:=Address (GetMsg (mywindow^.UserPort));
  180.     UNTIL myintuimessage<>NIL;
  181.  
  182.   Dies ist eigentlich logisch und auch schön strukturiert. Auf einem PC
  183.   mag dies das Maß aller Dinge sein. Nicht so auf unserem Amiga, der ja
  184.   bekanntermaßen ein Multitasking-System ist, ein Computer also, auf dem
  185.   viele Programme gleichzeitig laufen können.
  186.   Benutzt man nun obige Routine in einem Programm, so zeigt es sich, daß
  187.   parallel laufende Programme extrem langsamer werden, der Prozessor also
  188.   "in die Knie geht". Dies liegt daran, das hier ständig ein Befehl
  189.   abgearbeitet wird. Einfacher und wesentlich systemkonformer geht es mit
  190.   der Exec-Routine
  191.  
  192.   MessagePtr := WaitPort (port : MsgPortPtr);
  193.  
  194.                 Sie wartet so lange, bis eine Message im MsgPort ankommt.
  195.                 Bis dahin wird der Prozessor NICHT belastet !
  196.                 Das ist ein enormer Vorteil.
  197.  
  198.   Unsere Warteroutine sieht nun also so aus :
  199.  
  200.     myintuimessage:=Address (WaitPort (mywindow^.UserPort));
  201.     myintuimessage:=Address (GetMsg (mywindow^.UserPort));
  202.  
  203.   Nun werfen sich noch zwei Fragen auf :
  204.  
  205.   1. Was sollen eigentlich das "Address" vor den Funktionsaufrufen und
  206.      was sollen die Klammern drumherum ?
  207.   2. Warum folgt auf das WaitPort nochmal ein GetMsg ?
  208.  
  209.   Die Antworten :
  210.  
  211.   1. Das "Address" ist ein sogenannter "Cast", der aus der speziellen
  212.      Erwartung "MessagePtr" (was ja nicht zu IntuiMessagePtr passt !), eine
  213.      allgemeine Address macht, die auch mit einem IntuiMessagePtr
  214.      gleichgesetzt werden kann, ohne daß PCQ eine Fehlermeldung ausgibt.
  215.      Die Klammern um den Funktionsaufruf kennzeichnen die Variable, in
  216.      diesem Fall den Rückgabeparameter der Funktion, die "gecastet" werden
  217.      soll.
  218.   2. WaitPort liefert NICHT den Zeiger auf die angekommene Message zurück !
  219.      Diesen Fehler darf man AUF KEINEN Fall begehen ! Deshalb : nach jedem
  220.      WaitPort muß ein GetMsg kommen !
  221.      Hier möchte ich auch gleich darauf hinweisen, daß ich aus diesem
  222.      Grund mein "Include:Exec/Ports.i"-File ein wenig modifiziert habe,
  223.      und dort nun nur noch zu lesen ist :
  224.  
  225.      Procedure WaitPort (port : MessagePortPtr);
  226.  
  227.      Nur für diesen Kurs schreibe ich die WaitPorts in die ursprüngliche
  228.      Form um und deshalb kann es sein, daß ich es einmal vergesse und
  229.      in einem Beispiel auch eine WaitPort-Prozedur, statt einer
  230.      Funktion aufrufe ! Dies bitte ich im voraus zu entschuldigen !
  231.  
  232.   Nun aber, nach so viel grauer Theorie, zu dem Beispielprogramm :
  233.  
  234.         Program KursProgramm;
  235.  
  236.         { Listing für den AMIGAGadget/Purity - Pascalkurs ,            }
  237.         { Erste Schritte in der Messageprogrammierung                  }
  238.  
  239.         {$I "Include:Intuition/Intuition.I" }
  240.         {$I "Include:Exec/Libraries.I"      }
  241.  
  242.         VAR
  243.                 myscreen : ScreenPtr;
  244.                 mywindow : WindowPtr;
  245.  
  246.  
  247.         PROCEDURE CloseDisplay;
  248.  
  249.         VAR i : Integer;
  250.  
  251.         { Sollte ein Teil des Displays offen sein, dann wird er von }
  252.         { dieser Routine geschlossen.                               }
  253.  
  254.         BEGIN
  255.          IF mywindow<>NIL THEN
  256.           CloseWindow (mywindow);
  257.          IF myscreen<>NIL THEN
  258.           CloseScreen (myscreen);
  259.         END;
  260.  
  261.  
  262.         PROCEDURE BreakProgram (reason : STRING);
  263.  
  264.         { Diese Routine schließt alles bisher geöffnete, druckt den }
  265.         { Fehlergrund aus und bricht dann das Programm ab.          }
  266.  
  267.         BEGIN
  268.          CloseDisplay;
  269.          WRITELN ('Program error : ',reason);
  270.          Exit (42);
  271.         END;
  272.  
  273.         PROCEDURE OpenDisplay;
  274.  
  275.         { Diese Routine erstellt ein Display.                       }
  276.  
  277.         CONST
  278.                 mynewscreen : NewScreen = (0,0,640,256,2,0,1,HIRES,
  279.                                             CUSTOMSCREEN_f,NIL,
  280.                                             NIL,NIL,NIL);
  281.  
  282.         NewWin   : NewWindow =  (160,50,320,128,0,1,CLOSEWINDOW_f,
  283.                                 SMART_REFRESH+WINDOWDRAG+
  284.                                 ACTIVATE+SMART_REFRESH+WINDOWCLOSE,NIL,NIL,
  285.                                 "Click to Close - Dank Messages !",
  286.                                 NIL,NIL,0,0,0,0,CUSTOMSCREEN_f);
  287.  
  288.         BEGIN
  289.           myscreen := OpenScreen (Adr(mynewscreen));
  290.           IF myscreen=NIL THEN BreakProgram ("Couldn't open Screen");
  291.           NewWin.Screen:=myscreen;
  292.           mywindow := OpenWindow (Adr(NewWin));
  293.           IF mywindow=NIL THEN BreakProgram ("Couldn't open Window");
  294.         END;
  295.  
  296.  
  297.         PROCEDURE WarteAufKlick;
  298.  
  299.         { Unsere, oben entwickelte Warte-Routine.                       }
  300.  
  301.         VAR myintuimessage : IntuiMessagePtr;
  302.  
  303.         BEGIN
  304.          myintuimessage := Address (WaitPort (mywindow^.UserPort));
  305.          myintuimessage := Address (GetMsg (mywindow^.UserPort));
  306.          ReplyMsg (Address(myintuimessage));
  307.          { schön brav die Message zurückschicken und dann good bye !    }
  308.         END;
  309.  
  310.  
  311.         BEGIN
  312.           OpenDisplay;
  313.           WarteAufKlick;
  314.           CloseDisplay;
  315.         END.
  316.  
  317.   Es steht nun jedem frei, selbst mit den verschiedensten Flags zu
  318.   experimentieren, bis wir im nächsten Teil tiefer in die Materie
  319.   einsteigen.
  320.  
  321.   Weitere Informationen, Antworten auf Fragen und und und gibt es
  322.   natürlich im Leserforum des Gadgets oder direkt bei mir
  323.  
  324.     Andreas Neumann
  325.     Auf dem Ruhbühl 151
  326.     7997 Immenstaad
  327.  
  328.   Ansonsten bis zur nächsten Purity, wenn es wieder heißt
  329.  
  330.                        Ewig währt am längsten oder
  331.                        wie programmiere ich Pascal ?
  332.  
  333.   © 1992 by Andreas Neumann für AmigaGadget von Nils Kassube
  334.                             und Purity von Steppenbrand und Diesel
  335.  
  336.  
  337.  
  338.  
  339.  
  340.  
  341.  
  342.  
  343.  
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351.